#include "engine.h"
#include "script.h"
#include "core/stringhelper.h"
#include "file/file.h"
#include "3rdparty/angelscript/add_on/scriptarray/scriptarray.h"
#include "core/log.h"
#include "3rdparty/angelscript/add_on/scriptstdstring/scriptstdstring.h"
#include "3rdparty/angelscript/add_on/scriptmath/scriptmath.h"
#include "3rdparty/angelscript/add_on/scriptmath3d/scriptmath3d.h"
#include "entity/game.h"

script_manager_t* SCRIPTMAN=NULL;

script_registration_helper_t script_manager_t::helper_buf[1024];
int script_manager_t::helper_num=0;
const char* script_manager_t::function_group=NULL;
void RegisterJson(asIScriptEngine *engine);
void RegisterFloat4x4(asIScriptEngine *engine);
void RegisterFloat3(asIScriptEngine *engine);
void RegisterFloat4(asIScriptEngine *engine);

 void _cdecl MessageCallback(const asSMessageInfo *msg, void *param)
 {
	 log_t::log(_str("%s [%d:%d] : %s\n", msg->section,msg->row,msg->col,msg->message));
 }

void script_manager_t::init()
{
	ASSERT(SCRIPTMAN==NULL);
	SCRIPTMAN=new script_manager_t;
}

script_manager_t::script_manager_t()
{
	script_engine=asCreateScriptEngine(ANGELSCRIPT_VERSION);

	script_engine->SetMessageCallback(asFUNCTION(MessageCallback),NULL,asCALL_CDECL);

//	RegisterScriptString(script_engine);
	RegisterStdString(script_engine);
	RegisterScriptMath(script_engine);
	RegisterFloat3(script_engine);
	RegisterFloat4(script_engine);
	RegisterFloat4x4(script_engine);
	RegisterScriptArray(script_engine,true);
	RegisterJson(script_engine);
	int r=script_engine->RegisterInterface("IScriptObject"); assert( r >= 0 );

	register_functions();
	for (int n=0; n<4; ++n)
		global_context[n] = script_engine->CreateContext();
	load_scripts();
}

void script_manager_t::register_functions()
{
#ifdef LEO_DESIGNER
	const char* fgr="dummy";
	string scriptstr;
#endif
	for (int n=0; n<helper_num; ++n)
	{
		script_registration_helper_t* ptr=&helper_buf[n];
		int r=script_engine->RegisterGlobalFunction(ptr->function_name,ptr->function_ptr,asCALL_CDECL);
		ASSERTTXT(r>=0,"valami gyikja van a scriptfv regisztracionak");

#ifdef LEO_DESIGNER
		if (strcmp(fgr,ptr->function_group))
		{
			scriptstr+="\r\n\r\n";
			scriptstr+=ptr->function_group;
			scriptstr+="\r\n";
			fgr=ptr->function_group;
		}

		scriptstr+=ptr->function_name;
		scriptstr+="\r\n";
#endif
	}

//	helper_num=0;
//	helper_buf.clear();

#ifdef LEO_DESIGNER
	file_t scriptlog;
	scriptlog.open("scripts/scriptfunctions.txt","wb");
	scriptlog.writestring(scriptstr);
	scriptlog.close();
#endif
}

void script_manager_t::exit()
{
	delete SCRIPTMAN;
	SCRIPTMAN=NULL;
}

script_manager_t::~script_manager_t()
{
	for (int n=0; n<4; ++n)
		global_context[n]->Release();
	script_engine->Release();
}

void script_manager_t::load_scripts(int reinit)
{
	WIN32_FIND_DATA find_data;
	HANDLE file_search;

//	script_engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD,reinit);
//	script_engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD,1);

	asIScriptModule *mod = script_engine->GetModule("first_try", asGM_ALWAYS_CREATE);

	vector<string> filenames;
	file_search=FindFirstFile("scripts/*.cpp", &find_data);
	if (INVALID_HANDLE_VALUE!=file_search)
	{
		do
		{
			filenames.push_back(string("scripts/")+string(find_data.cFileName));
		} while (FindNextFile(file_search, &find_data));
	}

	// load script files
	for (unsigned n=0; n<filenames.size(); ++n)
	{
		string script;
		load_script_file(filenames[n].c_str(),script);
		if (mod->AddScriptSection(filenames[n].c_str(),script.c_str())<0)
		{
			ASSERTTXT(0,"valami baja van a script toltonek");
		}

	}

	int r=mod->Build();

	if (r>=0)
	{
		script_engine->DiscardModule(0);
		mod->SetName(0);
		execute_script_function("init_global");
	}

	ASSERTTXT(r>=0,"SCRIPT ERROR");
//	script_engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD,0);
}

void script_manager_t::load_script_file(const char* file_name,string& script)
{
	file_t f;
	f.open(file_name,"rb");

	unsigned int l=f.length();
	char* bytearray=new char[l+1];
	f.read(bytearray,l);
	bytearray[l]=0;
	script=bytearray;
	delete [] bytearray;
	f.close();
}


void script_manager_t::execute_script_function(const char* script_function)
{
	int funcId = script_engine->GetModule(0)->GetFunctionIdByName(script_function);

	ASSERTTXT(funcId>=0,_str("nincs %s nevu script fv",script_function));

	asIScriptContext* c=get_context();
	int r;
	r=c->Prepare(funcId); ASSERT(r>=0);
	r=c->Execute();ASSERT(r>=0);
}

asIScriptContext* script_manager_t::get_context()
{
	for (int n=0; n<4; ++n)
	{
		if (global_context[n]->GetState()!=asEXECUTION_ACTIVE)
			return global_context[n];
	}

	ASSERTTXT(0,"minden scriptcontext hasznalt\n");
	return NULL;
}


//type registrations
#include "json/json.h"

static void json_value_default_constructor(valueref& self)
{
	self.ptr=NULL;
}
static void objectref_default_constructor(objectref& self)
{
	self.objptr=NULL;
}


void set_float_value(valueref& v,float f)
{
	v.ptr->set_num(f);
}

void set_int_value(valueref& v,int i)
{
	v.ptr->set_int(i);
}

void set_bool_value(valueref& v,bool b)
{
	v.ptr->set_bool(b);
}

void set_string_value(valueref& v,const string& str)
{
	v.ptr->set_str(str);
}

float get_float_value(valueref& v)
{
	return v.ptr->get_num();
}

int get_int_value(valueref& v)
{
	return v.ptr->get_int();
}

bool get_bool_value(valueref& v)
{
	return v.ptr->get_bool();
}

objectref create_object(valueref& v)
{
	objectref o;
	o.objptr=&v.ptr->create_object();

	return o;
}


float3 get_float3_value(valueref& v)
{
	return float3((float)v.ptr->get_array().value_list[0].get_num(), (float)v.ptr->get_array().value_list[1].get_num(), (float)v.ptr->get_array().value_list[2].get_num());
}

float4 get_float4_value(valueref& v)
{
	return float4((float)v.ptr->get_array().value_list[0].get_num(), (float)v.ptr->get_array().value_list[1].get_num(), (float)v.ptr->get_array().value_list[2].get_num(), (float)v.ptr->get_array().value_list[3].get_num());
}
float4x4 get_float4x4_value(valueref& v)
{
	float4x4 m;
	for (int n=0; n<16; ++n)
	{
		m.m[n]=v.ptr->get_array().value_list[n];
	}

	return m;
}
void set_float3_value(valueref& v, const float3& vec)
{
	if (!v.ptr->is_array())
	{
		v.ptr->create_array();
		v.ptr->get_array().value_list.resize(3);
	}
	v.ptr->get_array().value_list[0].set_num(vec.x);
	v.ptr->get_array().value_list[1].set_num(vec.y);
	v.ptr->get_array().value_list[2].set_num(vec.z);
}

void set_float4_value(valueref& v, const float4& vec)
{
	if (!v.ptr->is_array())
	{
		v.ptr->create_array();
		v.ptr->get_array().value_list.resize(4);
	}
	for (int n=0; n<4; ++n)
		v.ptr->get_array()[n].set_num(vec[n]);
}

void set_float4x4_value(valueref& v,const float4x4& m)
{
	if (!v.ptr->is_array())
	{
		v.ptr->create_array();
		v.ptr->get_array().value_list.resize(16);
	}

	for (int n=0; n<16; ++n)
		v.ptr->get_array().value_list[n].set_num(m.m[n]);
}


const string& get_string_value(const valueref& v)
{
	return v.ptr->get_str();
}

objectref get_object_value(const valueref& v)
{
	objectref o;
	o.objptr=&v.ptr->get_object();
	return o;
}

void set_object_value(const valueref& v, const objectref& o)
{
	v.ptr->set_object(o.objptr);
}

int get_object_size(objectref& o)
{
	//	return 0;
	return (int)(o.objptr->pair_list.size());
}

void delete_object_at(objectref& o,uint32 index)
{
	o.objptr->pair_list[index].free();
	unordered_erase(o.objptr->pair_list,index);
}


valueref getvalue(json_object_t& o,const string& str)
{
	stringhash h=stringhash::get(str);
	if (!o.get_value(h))
		o.add(h);

	valueref v;
	v.ptr=o.get_value(h);
	return v;
}

valueref getvalue(json_object_t& o,unsigned index)
{
	if (o.pair_list.size()<=index)
		o.pair_list.resize(index+1);

	valueref v;
	v.ptr=&o.pair_list[index].val;
	return v;
}

valueref obj_getvalue_str(objectref& o,const string& str)
{
	return valueref(o.objptr->get_or_create_value(stringhash::get(str)));
}

bool obj_exist_at_str(objectref& o,const string& str)
{
	return o.objptr->get_value(stringhash::get(str))!=0;
}


valueref obj_getvalue_index(objectref& o,unsigned index)
{
	if (o.objptr->pair_list.size()<=index)
		o.objptr->pair_list.resize(index+1);

	valueref v;
	v.ptr=&o.objptr->pair_list[index].val;
	//	v.a=o.a+index;
	return v;
}

void RegisterJson(asIScriptEngine *engine)
{

	int r;

	//set(key,string)
	//set(key,bool)
	//set(key,float)
	//get(key,string)
	//get(key,bool)
	//get(key,float)

	//jsonvalue
	r = engine->RegisterObjectType("mapvalue", sizeof(valueref), asOBJ_VALUE | asOBJ_POD|asOBJ_APP_CLASS); assert( r >= 0 );
	// Register the constructors
	r = engine->RegisterObjectBehaviour("mapvalue", asBEHAVE_CONSTRUCT,  "void f()",asFUNCTION(json_value_default_constructor), asCALL_CDECL_OBJFIRST); assert( r >= 0 );

	//mapobject

	r = engine->RegisterObjectMethod("mapvalue", "float3 get_f3() const", asFUNCTION(get_float3_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "float4 get_f4() const", asFUNCTION(get_float4_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "float4x4 get_f4x4() const", asFUNCTION(get_float4x4_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "int  get_i() const", asFUNCTION(get_int_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "float get_f() const", asFUNCTION(get_float_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "bool get_b() const", asFUNCTION(get_bool_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "const string& get_str() const", asFUNCTION(get_string_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );

	r = engine->RegisterObjectMethod("mapvalue", "void set_f3(const float3& in) const", asFUNCTION(set_float3_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "void set_f4(const float4& in) const", asFUNCTION(set_float4_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "void set_f4x4(const float4x4& in) const", asFUNCTION(set_float4x4_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "void set_i(int) const", asFUNCTION(set_int_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "void set_f(float) const", asFUNCTION(set_float_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "void set_b(bool) const", asFUNCTION(set_bool_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "void set_str(const string& in) const", asFUNCTION(set_string_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	//	r = engine->RegisterObjectMethod("mapvalue", "void set_obj(?& in) const", asFUNCTION(set_object_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );


	// Register the type
	r = engine->RegisterObjectType("map", sizeof(objectref), asOBJ_VALUE | asOBJ_POD|asOBJ_APP_CLASS); assert( r >= 0 );
	//	r = engine->RegisterObjectType("map", sizeof(objectref), asOBJ_VALUE | asOBJ_POD|asOBJ_APP_PRIMITIVE ); assert( r >= 0 );
	// Register the constructors
	//	r = engine->RegisterObjectBehaviour("map", asBEHAVE_CONSTRUCT,  "void f()",asFUNCTION(objectref_default_constructor), asCALL_CDECL_OBJFIRST); assert( r >= 0 );

//	r = engine->RegisterObjectMethod("map", "mapvalue get_opIndex(uint) const", asFUNCTION(obj_getvalue_index), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("map", "mapvalue get_opIndex(const string& in) const", asFUNCTION(obj_getvalue_str), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("map", "mapvalue at(const string& in) const", asFUNCTION(obj_getvalue_str),asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("map", "bool exist_at(const string& in) const", asFUNCTION(obj_exist_at_str),asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("map", "int size() const", asFUNCTION(get_object_size), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("map", "void erase_at(int) const", asFUNCTION(delete_object_at), asCALL_CDECL_OBJFIRST); assert( r >= 0 );

	r = engine->RegisterObjectMethod("mapvalue", "map get_obj() const", asFUNCTION(get_object_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "void set_object(const map& in) const", asFUNCTION(set_object_value), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("mapvalue", "map create_object() const", asFUNCTION(create_object), asCALL_CDECL_OBJFIRST); assert( r >= 0 );

}


//float4x4
float3 get_float4x4_axis_x(const float4x4& mtx)
{
	return mtx.axis(0);
}
float3 get_float4x4_axis_y(const float4x4& mtx)
{
	return mtx.axis(1);
}
float3 get_float4x4_axis_z(const float4x4& mtx)
{
	return mtx.axis(2);
}
float3 get_float4x4_translate(const float4x4& mtx)
{
	return mtx.translate();
}

void set_float4x4_axis_x(float4x4& mtx, const float3& ax)
{
	mtx.axis(0)=ax;
}
void set_float4x4_axis_y(float4x4& mtx, const float3& ax)
{
	mtx.axis(1)=ax;
}
void set_float4x4_axis_z(float4x4& mtx, const float3& ax)
{
	mtx.axis(2)=ax;
}
void set_float4x4_translate(float4x4& mtx, const float3& t)
{
	mtx.translate()=t;
}

void float4x4_normalize(float4x4& mtx)
{
	mtx.normalize();
}

void float4x4_normalize_yzx(float4x4& mtx)
{
	mtx.normalize_yzx();
}

void float4x4_rotate(float4x4& mtx, const float3& axis, float angle)
{
	mtx.rotate(axis,angle);
}

void float4x4_identity(float4x4& mtx)
{
	mtx.identity();
}

void float4x4_invert(float4x4& dst, const float4x4& src)
{
	dst.invert(src);
}

void float4x4_mul(float4x4& dst, const float4x4& src1,const float4x4& src2)
{
	dst.mul(src1,src2);
}

float3 float4x4_transform(const float3& v,const float4x4& mtx)
{
	return mul4x3(v,mtx);
}

float4 float4x4_transform4x4(const float4& v,const float4x4& mtx)
{
	return mul(v,mtx);
}

void float4x4_scale(float4x4& mtx, float s)
{
	mtx.axis(0)*=s;
	mtx.axis(1)*=s;
	mtx.axis(2)*=s;
}

void float4x4_from_rotation(float4x4& mtx,float yaw,float pitch, float roll)
{
	mtx.from_rotation(yaw,pitch,roll);
}

void float4x4_to_rotation(const float4x4& mtx, float& yaw, float& pitch, float& roll)
{
	mtx.to_rotation(yaw,pitch,roll);
}

static void Float3DefaultConstructor(float3 *self)
{
	new(self) float3();
}

static void Float3CopyConstructor(const float3 &other, float3*self)
{
	new(self) float3(other);
}

static void Float3InitConstructor(float x, float y, float z, float3 *self)
{
	new(self) float3(x,y,z);
}


static void Float4DefaultConstructor(float4 *self)
{
	new(self) float4();
}

static void Float4CopyConstructor(const float4 &other, float4*self)
{
	new(self) float4(other);
}

static void Float4InitConstructor(float x, float y, float z,float w, float4 *self)
{
	new(self) float4(x,y,z,w);
}



float float3_length(const float3& src)
{
	return length(src);
}

float float3_length2(const float3& src)
{
	return length2(src);
}

float3 float3_mul(float skalar, const float3& vektor)
{
	return vektor*skalar;
}

float float3_dot(const float3& v1, const float3& v2)
{
	return dot(v1, v2);
}

float3 float3_cross(const float3& v1, const float3& v2)
{
	return cross(v1, v2);
}

void RegisterFloat3(asIScriptEngine* engine)
{
	int r;

	// Register the type
	r = engine->RegisterObjectType("float3", sizeof(float3), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CA); assert( r >= 0 );

	// Register the object properties
	r = engine->RegisterObjectProperty("float3", "float x", offsetof(float3, x)); assert( r >= 0 );
	r = engine->RegisterObjectProperty("float3", "float y", offsetof(float3, y)); assert( r >= 0 );
	r = engine->RegisterObjectProperty("float3", "float z", offsetof(float3, z)); assert( r >= 0 );

	// Register the constructors
	r = engine->RegisterObjectBehaviour("float3", asBEHAVE_CONSTRUCT,  "void f()",                     asFUNCTION(Float3DefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("float3", asBEHAVE_CONSTRUCT,  "void f(const float3 &in)",       asFUNCTION(Float3CopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("float3", asBEHAVE_CONSTRUCT,  "void f(float, float, float)",  asFUNCTION(Float3InitConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );

	// Register the operator overloads
	r = engine->RegisterObjectMethod("float3", "void opAddAssign(const float3 &in)", asMETHODPR(float3, operator+=, (const float3 &), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float3", "void opSubAssign(const float3 &in)", asMETHODPR(float3, operator-=, (const float3 &), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float3", "void opMulAssign(float)", asMETHODPR(float3, operator*=, (float), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float3", "void opDivAssign(float)", asMETHODPR(float3, operator/=, (float), void), asCALL_THISCALL); assert( r >= 0 );
	//r = engine->RegisterObjectMethod("float3", "bool opEquals(const float3 &in) const", asFUNCTIONPR(operator==, (const float3&, const float3&), bool), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float3", "float3 opAdd(const float3 &in) const", asMETHODPR(float3, operator+, (const float3 &) const, float3), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float3", "float3 opSub(const float3 &in) const", asMETHODPR(float3, operator-, (const float3 &) const, float3), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float3", "float3 opMul(float) const", asMETHODPR(float3, operator*, (float) const, float3), asCALL_THISCALL); assert( r >= 0 );
	//	r = engine->RegisterObjectMethod("float3", "float3 opMul_r(float) const", asFUNCTIONPR(operator*, (float, const float3&), float3), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float3", "float3 opMul_r(float) const", asFUNCTIONPR(float3_mul, (float, const float3&), float3), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float3", "float3 opDiv(float) const", asMETHODPR(float3, operator/, (float) const, float3), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float3", "void set(float,float,float) const", asMETHODPR(float3, set, (float,float,float), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float3", "void normalize()", asMETHODPR(float3, normalize, (), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterGlobalFunction("float dot(const float3& in, const float3& in)",asFUNCTIONPR(float3_dot,(const float3&,const float3&),float),asCALL_CDECL);
	r = engine->RegisterGlobalFunction("float3 cross(const float3& in, const float3& in)",asFUNCTIONPR(float3_cross,(const float3&,const float3&),float3),asCALL_CDECL);
	r = engine->RegisterGlobalFunction("float3 rotate(const float3& in, const float3& in,float)",asFUNCTIONPR(rotate,(const float3&,const float3&,float),float3),asCALL_CDECL);

	// Register the object methods
	r = engine->RegisterObjectMethod("float3", "float length() const", asFUNCTIONPR(float3_length,(const float3&),float), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float3", "float length2() const", asFUNCTIONPR(float3_length2,(const float3&),float), asCALL_CDECL_OBJFIRST); assert( r >= 0 );

}

void RegisterFloat4x4(asIScriptEngine *engine)
{
	int r;

	// Register the type
	r = engine->RegisterObjectType("float4x4", sizeof(float4x4), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CA); assert( r >= 0 );

	r = engine->RegisterObjectMethod("float4x4", "float3 get_axisX() const", asFUNCTION(get_float4x4_axis_x), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "float3 get_axisY() const", asFUNCTION(get_float4x4_axis_y), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "float3 get_axisZ() const", asFUNCTION(get_float4x4_axis_z), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "float3 get_translate() const", asFUNCTION(get_float4x4_translate), asCALL_CDECL_OBJFIRST); assert( r >= 0 );

	r = engine->RegisterObjectMethod("float4x4", "void set_axisX(const float3& in)", asFUNCTION(set_float4x4_axis_x), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "void set_axisY(const float3& in)", asFUNCTION(set_float4x4_axis_y), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "void set_axisZ(const float3& in)", asFUNCTION(set_float4x4_axis_z), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "void set_translate(const float3& in)", asFUNCTION(set_float4x4_translate), asCALL_CDECL_OBJFIRST); assert( r >= 0 );

	r = engine->RegisterObjectMethod("float4x4", "void normalize()", asFUNCTION(float4x4_normalize), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "void normalize_yzx()", asFUNCTION(float4x4_normalize_yzx), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "void scale(float s)", asFUNCTION(float4x4_scale), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "void rotate(const float3& in, float)", asFUNCTIONPR(float4x4_rotate,(float4x4&,const float3&,float), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "void identity()", asFUNCTION(float4x4_identity), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "void invert(const float4x4& in)", asFUNCTIONPR(float4x4_invert,(float4x4&,const float4x4&),void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "void mul(const float4x4& in,const float4x4& in)", asFUNCTIONPR(float4x4_mul,(float4x4&,const float4x4&,const float4x4&),void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "void from_rotation(float,float,float)", asFUNCTIONPR(float4x4_from_rotation,(float4x4&,float,float,float),void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "void to_rotation(float& out,float& out,float& out) const", asFUNCTIONPR(float4x4_to_rotation,(const float4x4&,float&,float&,float&),void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "float3 mul(const float3& in) const", asFUNCTIONPR(float4x4_transform,(const float3&,const float4x4&),float3), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4x4", "float4 mul(const float4& in) const", asFUNCTIONPR(float4x4_transform4x4,(const float4&,const float4x4&),float4), asCALL_CDECL_OBJLAST); assert( r >= 0 );


}


void RegisterFloat4(asIScriptEngine* engine)
{
	int r;

	// Register the type
	r = engine->RegisterObjectType("float4", sizeof(float4), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CA); assert( r >= 0 );

	// Register the object properties
	r = engine->RegisterObjectProperty("float4", "float x", offsetof(float4, x)); assert( r >= 0 );
	r = engine->RegisterObjectProperty("float4", "float y", offsetof(float4, y)); assert( r >= 0 );
	r = engine->RegisterObjectProperty("float4", "float z", offsetof(float4, z)); assert( r >= 0 );
	r = engine->RegisterObjectProperty("float4", "float w", offsetof(float4, w)); assert( r >= 0 );

	// Register the constructors
	r = engine->RegisterObjectBehaviour("float4", asBEHAVE_CONSTRUCT,  "void f()",                     asFUNCTION(Float4DefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("float4", asBEHAVE_CONSTRUCT,  "void f(const float4 &in)",       asFUNCTION(Float4CopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("float4", asBEHAVE_CONSTRUCT,  "void f(float, float, float,float)",  asFUNCTION(Float4InitConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );

/*
	// Register the operator overloads
	r = engine->RegisterObjectMethod("float4", "void set(float,float,float,float) const", asMETHODPR(float4, set, (float,float,float,float), void), asCALL_THISCALL); assert( r >= 0 );

	r = engine->RegisterObjectMethod("float4", "void opAddAssign(const float4 &in)", asMETHODPR(float4, operator+=, (const float4 &), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4", "void opSubAssign(const float4 &in)", asMETHODPR(float4, operator-=, (const float4 &), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4", "void opMulAssign(float)", asMETHODPR(float4, operator*=, (float), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4", "void opDivAssign(float)", asMETHODPR(float4, operator/=, (float), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4", "float4 opAdd(const float4 &in) const", asMETHODPR(float4, operator+, (const float4 &) const, float4), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4", "float4 opSub(const float4 &in) const", asMETHODPR(float4, operator-, (const float4 &) const, float4), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4", "float4 opMul(float) const", asMETHODPR(float4, operator*, (float) const, float4), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4", "float4 opMul_r(float) const", asFUNCTIONPR(float4_mul, (float, const float4&), float4), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4", "float4 opDiv(float) const", asMETHODPR(float4, operator/, (float) const, float4), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4", "void normalize()", asMETHODPR(float4, normalize, (), void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterGlobalFunction("float dot(const float4& in, const float4& in)",asFUNCTIONPR(float4_dot,(const float4&,const float4&),float),asCALL_CDECL);
	r = engine->RegisterGlobalFunction("float4 rotate(const float4& in, const float4& in,float)",asFUNCTIONPR(rotate,(const float4&,const float4&,float),float4),asCALL_CDECL);

	// Register the object methods
	r = engine->RegisterObjectMethod("float4", "float length() const", asFUNCTIONPR(float4_length,(const float4&),float), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("float4", "float length2() const", asFUNCTIONPR(float4_length2,(const float4&),float), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
*/
}

void script_log(const string& str)
{
	log_t::log(str.c_str());
}

#include "render/rendersystem.h"
float4x4 getprojectionmtx(float fov,float nearplane, float farplane)
{
	return get_projection_matrix(fov,1/RSYS->aspect,nearplane,farplane);
}

void load_scene(const string& scenename)
{
	GAME->scene_to_load=stringhelper::remove_extension(scenename);
}

script_fn_registering_begin(common)
register_script_fn("void script_log(const string& in)",script_log);
register_script_fn("void load_scene(const string& in)",load_scene);
register_script_fn("float4x4 getprojectionmtx(float fov,float nearplane, float farplane)",getprojectionmtx);
script_fn_registering_end
